﻿package com.fox2d 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.ui.Keyboard;
	
	/**
	 * ...
	 * @author Orlando Leite
	 */
	public class Game2D extends Sprite
	{
		protected var _camera:Camera2D;
		protected var charList:Array = new Array();
		protected var objList:Array = new Array();
		
		protected var _viewWidth:Number = 500;
		protected var _viewHeight:Number = 400;
		
		private var container:Sprite = new Sprite();
		private var masker:Sprite = new Sprite();
		
		// MAPS //
		private var bitmapGroundMap:Bitmap;
		private var bitmapRoofMap:Bitmap;
		private var walkMap:BitmapData;
		
		// OBJECTS //
		private var charsContainer:Sprite = new Sprite();
		
		private var background:Sprite = new Sprite();
		private var _bgcolor:uint = 0xCCCCCC;
		
		protected var _controller:GameController;
		
		public function Game2D() 
		{
			_camera = new Camera2D( updateCamera );
			
			masker.graphics.beginFill( 0x0 );
			masker.graphics.drawRect( 0, 0, 1, 1 );
			masker.graphics.endFill();
			
			updateViewport();
			
			container.mask = masker;
			
			bgcolor = _bgcolor;
			
			addChild( background );
			addChild( container );
			addChild( masker );
			
			addEventListener( Event.ADDED_TO_STAGE, init );
		}
		
		private function init( event:Event = null ):void
		{
			removeEventListener( Event.ADDED_TO_STAGE, init );
			
			_controller = GameController.controller( stage );
			
			// SET KEYS //
			_controller.addKey( KeyboardGame.UP, Keyboard.UP );
			_controller.addKey( KeyboardGame.DOWN, Keyboard.DOWN );
			_controller.addKey( KeyboardGame.LEFT, Keyboard.LEFT );
			_controller.addKey( KeyboardGame.RIGHT, Keyboard.RIGHT );
		}
		
		public function get controller():GameController
		{
			return _controller;
		}
		
		public function get viewWidth():Number
		{
			return _viewWidth;
		}
		
		public function set viewWidth( value:Number ):void
		{
			_viewWidth = value;
			updateBG();
		}
		
		public function set viewHeight( value:Number ):void
		{
			_viewHeight = value;
			updateBG();
		}
		
		public function get bgcolor():uint
		{
			return _bgcolor;
		}
		
		public function set bgcolor( value:uint ):void
		{
			_bgcolor = value;
			updateBG();
		}
		
		private function updateBG():void
		{
			background.graphics.beginFill( _bgcolor );
			background.graphics.drawRect( 0, 0, _viewWidth, _viewHeight );
			background.graphics.endFill();
		}
		
		protected function updateViewport():void
		{
			masker.width = _viewWidth;
			masker.height = _viewHeight;
			
			updateCamera();
		}
		
		protected function updateCamera():void
		{
			if ( container )
			{
				container.scaleX = container.scaleY = _viewWidth / 400 * camera.zoom;
				
				container.x = -( camera.x * container.scaleX - _viewWidth / 2 );
				container.y = -( camera.y * container.scaleY - _viewHeight / 2 );
			}
		}
		
		public function get camera():Camera2D
		{
			return _camera;
		}
		
		public function set map( value:Map2D ):void
		{
			var tileW:Number = value.tiles[0].width;
			var tileH:Number = value.tiles[0].height;
			
			var tempGroundMap:Sprite = new Sprite();
			var tempRoofMap:Sprite = new Sprite();
			var tempWalkMap:Sprite = new Sprite();
			
			for ( var a:int = 0; a < value.staticGround[0].length; a++ )
			{
				for ( var b:int = 0; b < value.staticGround.length; b++ )
				{
					// TILE GROUND MAP //
					var temp1:Bitmap = new Bitmap( value.tiles[value.staticGround[b][a]] );
					temp1.x = a * tileW;
					temp1.y = b * tileH;
					tempGroundMap.addChild( temp1 );
					
					// TILE ROOF MAP //
					var temp2:Bitmap = new Bitmap( value.tiles[value.staticRoof[b][a]] );
					temp2.x = a * tileW;
					temp2.y = b * tileH;
					tempRoofMap.addChild( temp2 );
					
					// WALK MAP //
					var temp3:Bitmap = new Bitmap( value.walk[value.staticGround[b][a]] );
					temp3.x = a * tileW;
					temp3.y = b * tileH;
					tempWalkMap.addChild( temp3 );
				}
			}
			
			// FINAL GROUND MAP //
			var tempData1:BitmapData = new BitmapData( tempGroundMap.width, tempGroundMap.height, true, 0x0 );
			tempData1.draw( tempGroundMap );
			bitmapGroundMap = new Bitmap( tempData1 );
			
			// FINAL ROOF MAP //
			var tempData2:BitmapData = new BitmapData( tempRoofMap.width, tempRoofMap.height, true, 0x0 );
			tempData2.draw( tempRoofMap );
			bitmapRoofMap = new Bitmap( tempData2 );
			
			// FINAL WALK MAP //
			walkMap = new BitmapData( tempWalkMap.width, tempWalkMap.height, true, 0x0 );
			walkMap.draw( tempWalkMap );
		}
		
		public function addLiveObject( char:LiveObject2D ):void
		{
			charList.push( char );
			charsContainer.addChild( char );
			char.init( this, walkMap );
		}
		
		public function removeLiveObject( char:LiveObject2D ):void
		{
			var list:Array = new Array();
			
			for ( var i:int = 0; i < charList.length; i++ )
			{
				if ( char != charList[i] ) list.push( charList[i] );
			}
			
			charsContainer.removeChild( char );
			charList = list;
		}
		
		public function addObject( object:Object2D ):void
		{
			objList.push( object );
			object.init( this, walkMap );
			charsContainer.addChild( object );
		}
		
		public function removeObject( char:Object2D ):void
		{
			
			var list:Array = new Array();
			
			for ( var i:int = 0; i < objList.length; i++ )
			{
				if ( char != objList[i] ) list.push( objList[i] );
			}
			
			charsContainer.removeChild( char );
			
			objList = list;
		}
		
		public function verifyWalkCollision( object:LiveObject2D ):Boolean
		{
			if ( walkMap.hitTest( new Point(), 1, object.hitter.bitmapData, new Point( object.x + object.hitter.x, object.y + object.hitter.y ), 1 ) )
			{
				return true;
			}
			
			return false;
		}
		
		public function verifyLiveObjectCollision( object:LiveObject2D ):Boolean
		{
			var collision:Boolean = false;
			
			for ( var i:int = 0; i < charList.length; i++ )
			{
				if ( object != charList[i] && object.hitter.bitmapData.hitTest( new Point( object.x + object.hitter.x, object.y + object.hitter.y ), 1, 
					 charList[i].hitter.bitmapData, new Point( charList[i].x + charList[i].hitter.x, charList[i].y + charList[i].hitter.y ), 1 ) )
				{
					if ( object.hit( charList[i] ) ) collision = true;
				}
			}
			
			return collision;
		}
		
		public function verifyObjectCollision( object:LiveObject2D ):Boolean
		{
			var collision:Boolean = false;
			
			for ( var i:uint = 0; i < objList.length; i++ )
			{
				if ( object.hitter.bitmapData.hitTest( new Point( object.x + object.hitter.x, object.y + object.hitter.y ), 1, 
					 objList[i].hitter.bitmapData, new Point( objList[i].x + objList[i].hitter.x, objList[i].y + objList[i].hitter.y ), 1 ) )
				{
					if ( object.hit( objList[i] ) ) collision = true;
				}
			}
			
			return collision;
		}
		
		public function startRender():void
		{
			if ( stage )
			{
				addEventListener( Event.ENTER_FRAME, update );
				container.addChild( bitmapGroundMap );
				container.addChild( charsContainer );
				container.addChild( bitmapRoofMap );
				updateViewport();
			}
			else
			{
				throw new Error( "FoxGame should be added to stage before call startRender" );
			}
		}
		
		public function stopRender():void
		{
			
		}
		
		public function update( event:Event ):void
		{
			for ( var i:int = 0; i < charList.length; i++ )
			{
				charList[i].update();
			}
		}
		
	}
	
}